package batch.common.email;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;

import javax.mail.internet.AddressException;

import batch.common.dnsclient.DNS;
import batch.common.dnsclient.DNSQuery;
import batch.common.dnsclient.UnknownNameException;
import batch.common.dnsclient.record.Address;
import batch.common.dnsclient.record.MailExchanger;
//javac -d /home01/sfc/batch/common/bin  -classpath /home01/sfc/lib/mail.jar:/home01/sfc/lib/ojdbc14.jar:/home01/sfc/lib/commons-lang-2.1.jar:/home01/sfc/lib/log4j-1.2.13.jar:/home01/sfc/lib/commons-dbutils-1.0.jar:/home01/sfc/batch/common/bin/:/home02/bea8/weblogic81/server/lib/weblogic.jar:/home01/sfc/lib/mail.jar:/home01/sfc/batch/common/bin/batch/common/email EmailCheck.java
/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */

public class EmailCheck {

  private String strDNSServer = "193.101.111.10";
  private String strFromEmail = "";
  private String strFromDomainName = "";
  private Vector vcDNSServer = null;

  /**
   * 생성자
   */
  public EmailCheck() {
    try {
      InputStream in = new FileInputStream("/etc/resolv.conf");
      EmailProperties p = new EmailProperties();
      p.load(in);
      in.close();
      strDNSServer = p.getProperty("nameserver", "193.101.111.10");
      vcDNSServer = p.getProperties();
    }
    catch (Exception e) {
      System.out.println(e.toString());
    }
  }

  /**
   * 생성자
   * @param strDNSServer String
   */
  public EmailCheck(String strDNSServer) {
    this.strDNSServer = strDNSServer;
  }

  /**
   * 생성자
   * @param strDNSServer String
   * @param strFromEmail String
   * @param strFromDomainName String
   */
  public EmailCheck(String strDNSServer, String strFromEmail,
                    String strFromDomainName) {
    this.strDNSServer = strDNSServer;
    this.strFromEmail = strFromEmail;
    this.strFromDomainName = strFromDomainName;
  }

  /**
   * javamail을 이용 email구문이 맞는지 체크 함수
   * @param strEmail String
   * @throws AddressException
   */
  public void ValidateMail(String strEmail) throws javax.mail.internet.
      AddressException {
    javax.mail.internet.InternetAddress iadd = new javax.mail.internet.
        InternetAddress(strEmail);
    iadd.validate();
  }

  /**
   * 메일서버 존재여부 체크 함수
   * @param strToEmail String
   * @return boolean
   */
  public boolean CheckEmailServer(String strToEmail) {
    try {
      ValidateMail(strToEmail);
      String strDomain = strToEmail.substring(strToEmail.indexOf("@") + 1,
                                              strToEmail.length());
	  checkDomainName(strDomain);
      if (vcDNSServer != null) {
        for (int i = 0; i < vcDNSServer.size(); i++) {
          String strTmpDNSServer = (String) vcDNSServer.elementAt(i);
          try{
            ArrayList arrlist = MXRecords(strDomain, strTmpDNSServer);
            if (arrlist.size() != 0) {
              return true;
            }
          }
          catch (UnknownNameException unex) {
        	// 알수없는 도메인 이름일 경우 Exception
            System.out.println(unex.toString());
            return false;
          }
          catch (SocketTimeoutException skto) {
        	  System.out.println(skto.toString());
        	  if (i==3) return false;
          }   
          catch (Exception e) {
            System.out.println(e.toString());
          }
        }
      }
    }
    catch (Exception x) {
      System.out.println(x.toString());
    }
    return false;
  }

  /**
   * 메일서버에 올바른 사용자 여부를 체크 함수
   * @param strToEmail String
   * @return boolean
   */
  public boolean CheckEmailUser(String strToEmail) {
    try {
      ValidateMail(strToEmail);
      String strDomain = strToEmail.substring(strToEmail.indexOf("@") + 1,
                                              strToEmail.length());
      checkDomainName(strDomain);
      ArrayList arrlist = MXRecords(strDomain);
      if (arrlist.size() != 0) {
        for (int count = 0; count < arrlist.size(); count++) {
          debug(arrlist.get(count).toString());
          if (ValidateUser(arrlist.get(count).toString(), strToEmail)) {
            return true;
          }
        }
      }
    }
    catch (Exception x) {
      System.out.println(x.toString());
    }
    return false;
  }

  /**
   * 메일서버에 정확한 사용자여부를 확인 하는 함수
   * @param strMailServer String
   * @param strToMail String
   * @throws Exception
   * @return boolean
   */
  private boolean ValidateUser(String strMailServer, String strToMail) throws
      Exception {
    DNSQuery query = new DNSQuery(strMailServer, DNS.TYPE_A,
                                  DNS.CLASS_IN);
    Socket socket = new Socket(strDNSServer, DNS.DEFAULT_PORT);
    socket.setSoTimeout(5000);
    sendQuery(query, socket);
    getResponse(query, socket);
    socket.close();

    Enumeration eaddr = query.getAnswers();
    InetAddress ipaddr = null;
    while (eaddr.hasMoreElements()) {
      try {
        Address SMTPServerAddress = (Address) eaddr.nextElement();
        ipaddr = SMTPServerAddress.getInetAddress();
        debug("ipaddr", "" + ipaddr);
        Socket socketIP = new Socket(ipaddr, 25);
        socketIP.setSoTimeout(5000);
        PrintStream printOut = new PrintStream(socketIP.
                                               getOutputStream());
        BufferedReader rederIn = new BufferedReader(new
            InputStreamReader(socketIP.getInputStream()));
        String m_rline;
        try {
          while ( (m_rline = rederIn.readLine()) != null) {
            debug(m_rline);
          }
        }
        catch (Exception e) {
        }
        printOut.print("HELO " + strFromDomainName + "\r\n");
        printOut.flush();
        String strReadLine1 = rederIn.readLine();
        debug(strReadLine1);
        if (!strReadLine1.startsWith("250")) {
          socketIP.close();
        }
        printOut.print("MAIL FROM:" + "<" + strFromEmail + "> " +
                       "\r\n");
        String strReadLine2 = rederIn.readLine();
        debug(strReadLine2);
        if (!strReadLine2.startsWith("250")) {
          socketIP.close();
        }
        printOut.print("RCPT TO:<" + strToMail + "> \r\n");
        String strReadLine3 = rederIn.readLine();
        debug(strReadLine3);
        if (!strReadLine3.startsWith("250")) {
          socketIP.close();
        }
        else {
          socketIP.close();
          return true;
        }
      }
      catch (Exception x) {
        System.out.println(x.toString());
      }
    }

    return false;
  }

  /**
   * 메일서버명을 arraylist에 가져오는 함수
   * @param strHostName String
   * @throws Exception
   * @return ArrayList
   */
  private ArrayList MXRecords(String strHostName) throws Exception {
    DNSQuery query = new DNSQuery(strHostName, DNS.TYPE_MX, DNS.CLASS_IN);
    Socket socket = new Socket(strDNSServer, DNS.DEFAULT_PORT);
    socket.setSoTimeout(5000);
    sendQuery(query, socket);
    getResponse(query, socket);
    socket.close();
    return getMXAddresses(query);
  }

  /**
   * 메일서버명을 arraylist에 가져오는 함수
   * @param strHostName String
   * @param strDNSServer String
   * @throws Exception
   * @return ArrayList
   */
  private ArrayList MXRecords(String strHostName, String strDNSServer) throws Exception {
    DNSQuery query = new DNSQuery(strHostName, DNS.TYPE_MX, DNS.CLASS_IN);
    Socket socket = new Socket(strDNSServer, DNS.DEFAULT_PORT);
    socket.setSoTimeout(5000);
    sendQuery(query, socket);
    getResponse(query, socket);
    socket.close();
    return getMXAddresses(query);
  }

  /**
   * DNSServer에 질의 함수
   * @param query DNSQuery
   * @param socket Socket
   * @throws IOException
   */
  private void sendQuery(DNSQuery query, Socket socket) throws IOException {
    BufferedOutputStream bufferedOut =
        new BufferedOutputStream(socket.getOutputStream());
    DataOutputStream dataOut = new DataOutputStream(bufferedOut);
    byte[] data = query.extractQuery();
    dataOut.writeShort(data.length);
    dataOut.write(data);
    dataOut.flush();
  }

  /**
   * DNSServer에 질의 결과를 받는 함수
   * @param query DNSQuery
   * @param socket Socket
   * @throws IOException
   */
  private void getResponse(DNSQuery query, Socket socket) throws IOException, UnknownNameException, ClassNotFoundException  {
    InputStream bufferedIn =
        new BufferedInputStream(socket.getInputStream());
    DataInputStream dataIn = new DataInputStream(bufferedIn);
    int responseLength = dataIn.readUnsignedShort();
    byte[] data = new byte[responseLength];
    dataIn.readFully(data);
    query.receiveResponse(data, responseLength);
  }

  /**
   * 메일서버명을 arrlist에 담는 함수
   * @param query DNSQuery
   * @return ArrayList
   */
  private ArrayList getMXAddresses(DNSQuery query) {
    Enumeration eanswer = query.getAnswers();
    ArrayList arrlist = new ArrayList();
    while (eanswer.hasMoreElements()) {
      MailExchanger mexchanger = (MailExchanger) eanswer.nextElement();
      Integer prefrence = new Integer(mexchanger.getPreference());
      String strAddr = mexchanger.getMX().toString();
      arrlist.add(strAddr);
    }
    return arrlist;
  }

  /**
   * 디버그 함수
   * @param strTitle String
   * @param strMessage String
   */
  private void debug(String strTitle, String strMessage) {
    if (false) {
      System.out.println(strTitle + ":" + strMessage);
    }
  }

  /**
   * 디버그 함수
   * @param strMessage String
   */
  private void debug(String strMessage) {
    debug("", strMessage);
  }

  /**
   * 도메인 이름 검사. 050103 추가
   * @param strDomain String
   * @throws Exception
   */
  private void checkDomainName(String strDomain) throws Exception {
    boolean bRe = false;
    debug("DomainName", strDomain);
    if (strDomain == null || strDomain.startsWith(".") ||
        strDomain.endsWith(".")) {
      bRe = true;
    }
    else {
      int iIn = strDomain.indexOf(".");
      while (iIn != -1) {
        if (strDomain.charAt(iIn + 1) == '.') {
          bRe = true;
          break;
        }
        iIn = strDomain.indexOf(".", iIn + 1);
      }
    }
    if (bRe) {
      throw new Exception("Domain name ERROR");
    }
  }

  /**
   * 메일서버 존재여부 체크 함수
   * @param strToEmail String
   * @return int
   
   	  --------[유효 이메일]--------
   	  correct email : 0
	  IOException, but correct email   : 99
	  
	  --------[유효성 재검증 필요]--------
	  sockettimeout, and it's need to be checked again :  -96
	  
	  --------[유효하지 않음 이메일]--------
   	  wrong character : -99
	  UnknownNameException : -97
	  the others Exception: -98(현재 서비스 되지 않는 도메인으로 추측됨),
	  						-95,-94,-93
  */
  
  public int chkEmail(String strEmail){
      int temp_len = strEmail.length();
      if( strEmail.indexOf('@') != strEmail.lastIndexOf('@') ||
          strEmail.indexOf('@') == 0 ||
          strEmail.indexOf('.') == 0 ||
          (strEmail.lastIndexOf('.')+1) == temp_len
        )
      {
          return -99;
      }

      int old_dotIndex=-1;
      for(int j1 = 0; j1 < temp_len; j1++)
      {
          if (j1 < strEmail.indexOf('@')) {
              if(!((strEmail.charAt(j1)>='0' && strEmail.charAt(j1)<='9') ||
                   (strEmail.charAt(j1)>='A' && strEmail.charAt(j1)<='Z') ||
                   (strEmail.charAt(j1)>='a' && strEmail.charAt(j1)<='z') ||
                    strEmail.charAt(j1)=='-' ||
                    strEmail.charAt(j1)=='_' ||
                    strEmail.charAt(j1)=='.'))
              {

                  return -99;
              }
          }

          if ( strEmail.charAt(j1) == '.' ) {
              if ( old_dotIndex+1 == j1 ) {
                  return -99;
              }

              old_dotIndex = j1;
          }
      }

      try 
      {
	      ValidateMail(strEmail);
	      String strDomain = strEmail.substring(strEmail.indexOf("@") + 1,strEmail.length());
		  checkDomainName(strDomain);
	      if (vcDNSServer != null) {
		        for (int i = 0; i < vcDNSServer.size(); i++) {
		          String strTmpDNSServer = (String) vcDNSServer.elementAt(i);
		          try{
		            ArrayList arrlist = MXRecords(strDomain, strTmpDNSServer);
		            if (arrlist.size() != 0) {
		              return 0;
		            }else{
		              return -98; //lycos.co.uk 등 ..현재 서비스 하지 않는 도메인 인듯
		            }
		          }
		          catch (UnknownNameException unex) {
		              // 알수없는 도메인 이름일 경우 Exception
		        	  System.out.println(unex.toString());
		        	  return -97;
		          }
		          catch (SocketTimeoutException skto) {
		              System.out.println(skto.toString());
		              if (i==(vcDNSServer.size()-1)) return -96; // resolv.conf에 등록된 (namserver수 -1)
	             }
		          catch (ClassNotFoundException cnf) {
		        	  System.out.println(cnf.toString());
		        	  return 99; //java.io.IOException: Unknown DNSRR : 리다이렉션 되는 URL , 유효 이메일로 간주
		          }
		          catch (Exception e) {
		            System.out.println(e.toString());
		            return -95; //Server Failed , 기타
		          }
		        }
	      	}
	    }
	    catch (Exception x) {
	      System.out.println(x.toString());
	      return -94;
	    }
	    return -93;
  }

}
